﻿using System;
using System.Collections;
using System.Collections.Generic;

    /// <summary>
    /// 弱引用字典:用于能够保持对应的引用同时允许GC在必要时释放对象，回收内存
    /// </summary>
    /// <typeparam name="K"></typeparam>
    /// <typeparam name="V"></typeparam>
public class WeakDictionary<K,V>
{
    //弱引用，能够保持对应的引用同时允许GC在必要时释放对象，回收内存
    private Dictionary<K, WeakReference> weakMap = new Dictionary<K, WeakReference>();
    public V this[K key]
    {
        get
        {
            WeakReference refer = this.weakMap[key];
                V v = (V)(refer.Target);
                if (v != null)
                {
                    return (V)(refer.Target);
            }
            return default(V);
        }

        set
        {
            this.Set(key, value);
        }
    }

    private ICollection<K> Keys()
    {
        return this.weakMap.Keys;
    }

    private void Set(K key,V value)
    {
        if (this.weakMap.ContainsKey(key))
        {
            if(this.weakMap[key].Target != null)
            {
                throw new ArgumentException("key exists");
            }
            this.weakMap[key].Target = value;
        }
        else
        {
            WeakReference wr = new WeakReference(value);
            this.weakMap.Add(key, wr);
        }
    }

    private ICollection<V> Values()
    {
        List<V> list = new List<V>();
        foreach(K key in this.weakMap.Keys)
        {
            list.Add((V)(this.weakMap[key].Target));
        }
        return list;
    }

    public void TryRemove(K key)
    {
        if (this.weakMap.ContainsKey(key)) this.weakMap.Remove(key);
    }

    public bool ContainsKey(K key)
    {
        return this.weakMap.ContainsKey(key);
    }
    public bool Remove(K key)
    {
        return this.weakMap.Remove(key);
    }

    public bool TryGetValue(K key,out V value)
    {
        WeakReference wr;
        if(!this.weakMap.TryGetValue(key,out wr))
        {
            value = default(V);
            return false;
        }
        if(wr.Target != null)
        {
            value = (V)wr.Target;
            return true;
        }
        value = default(V);
        return false;
    }

    public void GC()
    {
        List<K> list = new List<K>();
        foreach (var p in this.weakMap)
        {
            if (p.Value.Target == null) list.Add(p.Key);
        }
        for (int i = 0; i < list.Count; i++) this.weakMap.Remove(list[i]);
    }

}
